#include "Dwarf.Unmanaged.Mpi.h"

using namespace std;

// The settings for this dwarf.
static Settings* settings;

// Get settings from the command line.
static int getSettings(int argc, char** argv, Solver *solver) 
{
    int error = 0;
    if (solver->isRootThread) 
    {
        settings = new Settings();
        if (settings->init(argc,argv,solver)) 
        {            
            delete settings;
            error = 1;
        }
    }
    //Distribute error if that occurred while parsing.
    MPI_Bcast(&error, 1, MPI_INT, NUMBER_ROOT_PROCESS, MPI_COMM_WORLD);
    if (error == 1 ) return -1;

    
    int length;
    if(solver->isRootThread)
    {
        length = solver->graph->getLength();
    }
    //Distribute the number of states.
    MPI_Bcast(&length, 1, MPI_INT, NUMBER_ROOT_PROCESS, MPI_COMM_WORLD);
    
    if(!solver->isRootThread)
    {
        solver->graph = new Graph(length);
    }

    //Distribute the array of counts.
    MPI_Bcast(solver->graph->arrayOfcounts, length, MPI_INT, NUMBER_ROOT_PROCESS, MPI_COMM_WORLD);
    
    //Distribute the matrix of edges 
    for(int i = 0; i< length; i++)
    {   
        if(!solver->isRootThread)
        {
            solver->graph->edgesMatrix[i] = new int[solver->graph->arrayOfcounts[i]];
        }
        MPI_Bcast(solver->graph->edgesMatrix[i], solver->graph->arrayOfcounts[i], MPI_INT, NUMBER_ROOT_PROCESS, MPI_COMM_WORLD);
    }
    
    return 0;
}

// Point of the program start.
void main(int argc, char** argv)
{   
    // initialize MPI
    MPI_Init(&argc, &argv); 

    Solver* solver = new Solver();        
    // Get settings from the command line.
    if (getSettings(argc, argv, solver)) 
    {
        delete solver;
        exit(-1);
    }


    MPI_Barrier(MPI_COMM_WORLD);

    if (solver->isRootThread) 
    {
        settings->start();                   // Start new time count.
    }

    solver->solve();                         // Solve the current problem.

    MPI_Barrier(MPI_COMM_WORLD);
    
    double time = 0;
    if (solver->isRootThread) 
    {   
        time = settings->finish();           // Stop the time count and write results.
    }

    solver->gatherResults();                 // Gather on root processor

    if (solver->isRootThread) 
    {   
        settings->writeResult(solver,time);
        delete settings;
    } 

    delete solver;

    MPI_Finalize();
}